<template>
  <div class="map-tools">
    <button
      @click="measureDist"
      :class="currentTool == 'measureDist' ? 'current-tool' : ''"
    >
      <img src="/src/assets/images/map-tools/距离测量.png" alt="" />
    </button>
    <button
      @click="measureArea"
      :class="currentTool == 'measureArea' ? 'current-tool' : ''"
    >
      <img src="/src/assets/images/map-tools/面积.png" alt="" />
    </button>
    <button @click="clearPaint">
      <img src="/src/assets/images/map-tools/清除.png" alt="" />
    </button>
    <div class="flex-grow"></div>
    <button @click="exportImg">
      <img src="/src/assets/images/map-tools/导出图片.png" alt="" />
    </button>
  </div>
</template>

<script setup>
import { ref, toRefs, nextTick } from 'vue'
import { useMapStore } from '@/stores/map' // 使用pinia
const { map } = toRefs(useMapStore())
const currentTool = ref('') // 工具箱

var sketch // 当前绘制的要素 @type {ol.Feature}
var measureTooltipElement // 测量工具提示框对象 @type {Element}
var measureTooltip // 测量工具中显示的测量值 @type {ol.Overlay}
var source

// 此时首页已经完成地图初始化, map有了值
nextTick(() => {
  source = map.value.getLayers().getArray()[4].getSource()
})
var draw // global so we can remove it later
/*---------------- 测量 ---------------*/
function measureDist() {
  if (draw) {
    map.value.getInteractions().pop() //移除绘制图形
  }
  if (currentTool.value == 'measureDist') {
    currentTool.value = ''
    draw = null
  } else {
    createMeasureTooltip() //创建测量工具提示框
    currentTool.value = 'measureDist'
    addInteraction('LineString') //添加绘图进行测量
  }
}
function measureArea() {
  if (draw) {
    map.value.getInteractions().pop() //移除绘制图形
    draw = null
  }
  if (currentTool.value == 'measureArea') {
    currentTool.value = ''
  } else {
    createMeasureTooltip() //创建测量工具提示框
    currentTool.value = 'measureArea'
    addInteraction('Polygon') //添加绘图进行测量
  }
}
function clearPaint() {
  source.clear()
  map.value.getOverlays().clear() // 清空overlayer
  createMeasureTooltip() //创建测量工具提示框
}
/*---------------- 导出图片 ---------------*/
function exportImg() {
  map.value.once('postcompose', function (event) {
    var canvas = event.context.canvas
    canvas.toBlob(function (blob) {
      saveAs(blob, 'map.png')
    })
  })
  map.value.renderSync()
}
/**
 * 加载交互绘制控件函数
 */
function addInteraction(type) {
  // 'Polygon' / 'LineString'
  draw = new ol.interaction.Draw({
    source: source, //测量绘制层数据源
    type, //几何图形类型
    /** @type {ol.geom.GeometryType} */ style: new ol.style.Style({
      //绘制几何图形的样式
      fill: new ol.style.Fill({
        color: 'rgba(255, 255, 255, 0.2)',
      }),
      stroke: new ol.style.Stroke({
        color: 'rgba(0, 0, 0, 0.5)',
        lineDash: [10, 10],
        width: 2,
      }),
      image: new ol.style.Circle({
        radius: 5,
        stroke: new ol.style.Stroke({
          color: 'rgba(0, 0, 0, 0.7)',
        }),
        fill: new ol.style.Fill({
          color: 'rgba(255, 255, 255, 0.2)',
        }),
      }),
    }),
  })
  map.value.addInteraction(draw)

  var listener
  //绑定交互绘制工具开始绘制的事件
  draw.on(
    'drawstart',
    function (evt) {
      // set sketch
      sketch = evt.feature //绘制的要素

      /** @type {ol.Coordinate|undefined} */
      var tooltipCoord = evt.coordinate // 绘制的坐标
      //绑定change事件，根据绘制几何类型得到测量长度值或面积值，并将其设置到测量工具提示框中显示
      listener = sketch.getGeometry().on('change', function (evt) {
        var geom = evt.target //绘制几何要素
        var output
        if (geom instanceof ol.geom.Polygon) {
          output = formatArea(/** @type {ol.geom.Polygon} */ (geom)) //面积值
          tooltipCoord = geom.getInteriorPoint().getCoordinates() //坐标
        } else if (geom instanceof ol.geom.LineString) {
          output = formatLength(/** @type {ol.geom.LineString} */ (geom)) //长度值
          tooltipCoord = geom.getLastCoordinate() //坐标
        }
        measureTooltipElement.innerHTML = output //将测量值设置到测量工具提示框中显示
        measureTooltip.setPosition(tooltipCoord) //设置测量工具提示框的显示位置
      })
    },
    this
  )
  //绑定交互绘制工具结束绘制的事件
  draw.on(
    'drawend',
    function (evt) {
      measureTooltipElement.className = 'tooltip tooltip-static' //设置测量提示框的样式
      measureTooltip.setOffset([0, -7])
      // unset sketch
      sketch = null //置空当前绘制的要素对象
      // unset tooltip so that a new one can be created
      measureTooltipElement = null //置空测量工具提示框对象
      createMeasureTooltip() //重新创建一个测试工具提示框显示结果
      ol.Observable.unByKey(listener)
    },
    this
  )
}

/**
 *创建一个新的测量工具提示框（tooltip）
 */
function createMeasureTooltip() {
  if (measureTooltipElement) {
    measureTooltipElement.parentNode.removeChild(measureTooltipElement)
  }
  measureTooltipElement = document.createElement('div')
  measureTooltipElement.className = 'tooltip tooltip-measure'
  measureTooltip = new ol.Overlay({
    element: measureTooltipElement,
    offset: [0, -15],
    positioning: 'bottom-center',
  })
  map.value.addOverlay(measureTooltip)
}

/**
 * 让用户切换选择测量类型（长度/面积）
 * @param {Event} e Change event.
 */
/**
 * 测量长度输出
 * @param {ol.geom.LineString} line
 * @return {string}
 */
var formatLength = function (line) {
  var length
  var sphere = new ol.Sphere()
  //若使用测地学方法测量
  var sourceProj = map.value.getView().getProjection() //地图数据源投影坐标系
  length = sphere.getLength(line, {
    projection: sourceProj,
    radius: 6378137,
  })
  var output
  if (length > 100) {
    output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km' //换算成KM单位
  } else {
    output = Math.round(length * 100) / 100 + ' ' + 'm' //m为单位
  }
  return output //返回线的长度
}
/**
 * 测量面积输出
 * @param {ol.geom.Polygon} polygon
 * @return {string}
 */
var formatArea = function (polygon) {
  var area
  var sphere = new ol.Sphere()
  //使用测地学方法测量
  var sourceProj = map.value.getView().getProjection() //地图数据源投影坐标系
  var geom = /** @type {ol.geom.Polygon} */ (
    polygon.clone().transform(sourceProj, 'EPSG:4326')
  ) //将多边形要素坐标系投影为EPSG:4326
  area = Math.abs(
    sphere.getArea(geom, { projection: sourceProj, radius: 6378137 })
  ) //获取面积

  var output
  if (area > 10000) {
    output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>' //换算成KM单位
  } else {
    output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>' //m为单位
  }
  return output //返回多边形的面积
}
</script>

<!-- 工具箱-测量 -->
<style>
/**
  * 提示框的样式信息
  */
.tooltip {
  position: relative;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  color: white;
  padding: 4px 8px;
  opacity: 0.7;
  white-space: nowrap;
}

.tooltip-measure {
  opacity: 1;
  font-weight: bold;
}

.tooltip-static {
  background-color: #ffcc33;
  color: black;
  user-select: none;
  border: 1px solid white;
}

.tooltip-measure:before,
.tooltip-static:before {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: '';
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}

.tooltip-static:before {
  border-top-color: #ffcc33;
}
</style>

<style scoped>
.flex-grow {
  /* flex-grow: 1; */
  width: 10px;
}
.map-tools {
  position: absolute;
  display: flex;
  right: 5px;
  top: 172px;
  background-color: rgba(255, 255, 255, 0.5);
  border-radius: 4px;
  padding: 2px;
  z-index: 3;
}
.map-tools button {
  display: block;
  margin: 1px;
  padding: 0;
  color: #fff;
  /* font-size: 22px; */
  font-weight: 700;
  text-decoration: none;
  text-align: center;
  height: 25px;
  width: 25px;
  /* line-height: 0.4em; */
  background-color: rgba(0, 60, 136, 0.5);
  border-radius: 2px;
  border: none;
}
.map-tools button:hover {
  text-decoration: none;
  background-color: rgba(0, 60, 136, 0.7);
}
.map-tools button.current-tool {
  background-color: rgba(0, 60, 136, 0.7);
}
</style>
